#!/usr/bin/perl
#
# usage:
#   wget -q --post-data="2chTrip hoge 2 node1 node2 node3 node4" -O - http://localhost/cgi-bin/limura/Game/runJob.cgi'?USER1'
#   options: ProblemType Problem redundancyNum node [node ...]
#
#   JSON
#      {
#        "Request":"RunJob",
#        "JobType":"2chTrip",
#        "Problem":"CLOUDWAR",
#        "Redundancy":1,
#        "UserName":"USER1",
#        "OptionString":"hoge",
#        "Point":10,
#        "Nodes":[
#          "node1", "node2", "node3", "node4"
#        ]
#      }

require 'config.ph';

$SIG{'CHLD'} = sigchld_handler;

$option = join(' ', @ARGV);
while(<STDIN>){
	s/\r?\n$//;
	$option .= " ". $_;
}

if($option =~ m/\{/){ # trigger of JSON
	$jsonObj = from_json($option);
	if(defined($jsonObj) && defined($jsonObj->{"Request"}) && $jsonObj->{"Request"} eq 'RunJob'){
		$problemType = $jsonObj->{"JobType"};
		$problem = $jsonObj->{"Problem"};
		$redundancy = $jsonObj->{"Redundancy"};
		$nodesList = $jsonObj->{"Nodes"};
		@node = @$nodesList;
		$optionString = $jsonObj->{"OptionString"};
		$userName = $jsonObj->{"UserName"};
		$point = $jsonObj->{"Point"};
	}
	if($problemType eq ''){
		&PrintError("invalid JSON request");
		exit(0);
	}
}else{
	($problemType, $problem, $redundancy, @node) = split(/\s+/, $option);
}
$masterURL = &GetMasterURL($userName);
if($masterURL eq ''){
	&PrintError("userName '$userName' is not registered.");
	exit(0);
}

if($#node < 0){
	&PrintError("no available node found.");
	exit(0);
}
if($redundancy > ($#node + 1) || $redundancy <= 0){
	&PrintError("reduncancy num($redundancy) too big or small.");
	exit(0);
}

undef(@jobs);
$n = int(($#node+1) / $redundancy);
$n++ if(($#node+1) % $redundancy > 0);
foreach $r (1 .. $redundancy){
	$nodes = '';
	foreach $i ( ($r - 1)*$n .. $r*$n - 1){
		$nodes .= ' '. $node[$i];
	}
	$result = join('', `$WGET -q -O - --post-data='$problemType $problem $nodes' $masterURL/solve.cgi'?'$userName`);
	#$result = join('', `./solve $problemType $problem $nodes`);
	# process queueing. id: \"$ID\"
	if($result =~ m/^process queueing\. id: "([^"]+)"/){
		push(@jobs, $1);
	}else{
		$error .= $result;
	}
}
if($#jobs < 0){
	&PrintError("Master solve process return error: $error");
	exit(0);
}

$jobID = &createJobID($problemType, $problem, $redundancy, $optionString, $userName, $point);
unless(open(JOB, ">$HOME_DIR/Game/jobs/$jobID")){
	foreach $job (@jobs){
		`$WGET -q -O - --post-data='$job' $masterURL/destroyJob.cgi'?'$userName`;
		#`./destroyJob $job`;
	}
	&PrintError("can not create job file. $HOME_DIR/Game/jobs/$jobID.");
	exit(0);
}
foreach $job (@jobs){
	print JOB "$job\n";
}
close(JOB);
&PrintResult("$jobID queued.", { JobID => $jobID, Redundancy => $redundancy
	, JobType => $problemType, Problem => $problem, Point => $point
	, OptionString => $optionString });
&daemon();

while(1){
	sleep(1);
	$result = join('', `$WGET -q -O - $masterURL/state.cgi'?'$userName`);
	$result =~ s/\r?\n//g;
	$result =~ m/({.*})/;
	last if($1 eq '');
	$jsonObj = from_json($1);
	$done = 0;
	$success = 0;
	foreach $job (@jobs){
		if(defined($jsonObj->{$job})){
			if($jsonObj->{$job}->{"Result"} ne ''){
				$done++ if($jsonObj->{$job}->{"Result"} ne 'not solved.');
				$success = 1 if($jsonObj->{$job}->{"Result"} =~ m/^success\.?$/);
			}
		}else{
			# Result not found ==> error?
			last;
		}
	}
	last if($success || $done == ($#jobs + 1));
}
foreach $job (@jobs){
	`$WGET -q -O - --post-data='$job' $masterURL/destroyJob.cgi'?'$userName`;
}
if($success){
	&AddPoint($userName, $point);
}
exit(0);

sub createJobID{
	my($problemType, $problem, $redundancy, $optionString, $userName, $point) = @_;
	#my($time) = scalar(localtime());
	my($time) = time();
	$time =~ s/\s+/_/g;
	return join('_', $optionString, $userName, $point, $problemType, $problem, $redundancy, $time);
}

# become daemon
sub daemon{
        open STDIN, "/dev/null";
        open STDOUT, ">>/dev/null";
        #open STDOUT, ">>stdout_log";
        open STDERR, ">>/dev/null";

        if($pid = fork()){
                exit(0);
        }elsif(defined($pid)){
                setsid;
                return 1;
        }else{
                # filed.
                return 0;
        }
        return 0;
}

# run one Master Job (call wget process for Master runJob CGI)
sub runMasterJob {
        my($url, $putData, $outFile) = @_;
        my($pid);
        if($pid = fork()){
                # parent
        }elsif(defined($pid)){
                # child
                #open(STDOUT, ">&=". $pipe->fileno());
                exec($WGET, "-q", "-O", $outFile, "--post-data='$putData'", $url);
                exit(0);
                return undef;
        }else{
                return undef;
        }
	$workers{$pid} = $outFile;
        return ($pid, $outFile);
}
# for wget process(reading for worker node process) exit.
sub sigchld_handler {
        my($pid) = wait;
        return if($pid < 0);
        delete($workers{$pid});
        my($key);
        foreach $key (keys(%workNodes)){
                if($workNodes{$key} == $pid){
                        &deleteNodeJob($key, $workProblems{$pid});
                        delete($workProblems{$pid});
                        delete($workNodes{$key});
                        last;
                }
        }
        if(&checkSetter() != 0){
                # success.
                my($node);
                foreach $node (keys(%workNodes)){
                        &killJob($ID, $node);
                }
        }
}
